/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  TinyString.cpp
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2020/06/12
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#include "TinyString.h"
namespace qb {
namespace base {
TinyString::~TinyString() { destroy(); }

TinyString::TinyString(const char* str) : m_data(nullptr) { assign(str, -1); }

TinyString::TinyString(const char* str, int len) : m_data(nullptr) {
  assign(str, len);
}

TinyString::TinyString(const std::string& str) : m_data(nullptr) {
  assign(str.c_str(), str.size());
}

TinyString::TinyString(const ThisType& str) : m_data(nullptr) {
  assign(str.c_str(), str.size());
}

TinyString::TinyString(ThisType&& str) : m_data(str.m_data) {
  str.m_data = nullptr;
}

TinyString::TinyString() : m_data(nullptr) {}

qb::base::TinyString& TinyString::operator=(ThisType& str) {
  assign(str.c_str(), str.size());
  return *this;
}

TinyString& TinyString::operator=(ThisType&& str) {
  std::swap(m_data, str.m_data);
  return *this;
}

TinyString& TinyString::operator=(const char* str) {
  assign(str, -1);
  return *this;
}

TinyString& TinyString::operator+=(const ThisType& str) {
  assign_plus(c_str(), size(), str.c_str(), str.size());
  return *this;
}

TinyString& TinyString::operator+=(const char* str) {
  assign_plus(c_str(), size(), str, -1);
  return *this;
}

int TinyString::bytes() const {
  if (m_data == nullptr || istiny()) return 4;
  int len = size();
  return len >= TinyLength ? (sizeof(const char*) + len + 3)
                           : (sizeof(const char*) + len + 2);
}

bool TinyString::assign_plus(const char* str, int len, const char* post,
                             int postLen) {
  len = str ? (len <= 0 ? strlen(str) : len) : 0;
  postLen = post ? (postLen <= 0 ? strlen(post) : postLen) : 0;
  int total = len + postLen;
  if (total <= 0) {
    destroy();
    m_data = nullptr;
    return true;
  }
  if (total <= 3) {
    char raw[4] = {0, 0, 0, 0};
    if (len > 0) {
      memcpy(raw, str, len);
    }
    if (postLen > 0) {
      memcpy(raw + len, post, postLen);
    }
    raw[3] = 0;
    destroy();
    memcpy(m_raw, raw, 4);
    return true;
  }
  total = total >= MaxLength ? MaxLength : total;
  int extra = 0;
  char* data = new (std::nothrow) char[extra + total + 1];
  char* dest = data + extra;
  char* end = data + extra + total;
  if (len > 0) {
    memcpy(dest, str, len);
  }
  if (postLen > 0) {
    memcpy(dest + len, post, postLen);
  }
  *end = '\0';
  set_length(data, total);
  destroy();
  set_pointer(data);
  return true;
}

bool TinyString::assign(const char* str, int len) {
  if (len < 0) len = str ? strlen(str) : 0;
  if (len <= 0) {
    destroy();
    m_data = nullptr;
    return true;
  } else if (len <= 3) {
    char raw[4] = {0, 0, 0, 0};
    memcpy(raw, str, len);
    raw[3] = 0;
    destroy();
    memcpy(m_raw, raw, 4);
    return true;
  }
  len = len >= MaxLength ? MaxLength : len;
  int extra = 0;
  char* data = new (std::nothrow) char[extra + len + 1];
  if (data) {
    memcpy(data + extra, str, len);
    data[extra + len] = 0;
    set_length(data, len);
    destroy();
    set_pointer(data);
    return true;
  }
  return false;
}
}  // namespace base
}  // namespace qb
